package com.rfsp.common.jwt;

import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.mgt.SubjectFactory;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ResourceUtils;
import org.springframework.web.servlet.config.annotation.*;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;

import javax.servlet.Filter;
import java.util.*;

//@Configuration
//@EnableWebMvc
public class ShiroConfig implements WebMvcConfigurer {

    @Autowired
    ShiroInterceptor shiroInterceptor;
    String jwtFilter = "jwtFilter";

    String[] anonPath = {
            "/**/*.js",
            "/**/*.css",
            "/**/*.html",
            "/**/*.jpg",
            "/**/*.png",
            "/**/*.gif",

            "/static/**",



            "/swagger-ui.html",
            "/swagger-resources/**",
            "/swagger/**",

            "/v2/api-docs",
            "/webjars/**",

            //"/",
            //"/actuator/**",
            //"/test/**",

            "/login",
            "/logout",
            "/403",
            "/index",
            "/page",

            "/download/apk",
            "/portal/**",

            "/monitor/console",
            "/monitor/app2/state",
            "/monitor/rfsp/state",
            "/monitor/uump/state",


            //"/creditor/**/**",
            //"/**/**/*Rule",
            //"/my/index",
            //"/rule/**",
            //"/my/test",
            //"/my/test1",
            //"/**/**",
            "/unauthorization/**",
            "/error",

            "/chatSocket",

            //登录相关
            "/my/auth/login",
            "/my/auth/logout",
            "/my/auth/validateCode",

            "/doc/**"
    };

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        // 配置模板资源路径
        registry.addResourceHandler("/templates/**").addResourceLocations(ResourceUtils.CLASSPATH_URL_PREFIX+"/templates/");
        registry.addResourceHandler("/static/**").addResourceLocations(ResourceUtils.CLASSPATH_URL_PREFIX+"/static/");

        registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
    }
    /**
     * 添加拦截器
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //拦截路径可自行配置多个 可用 ，分隔开
        InterceptorRegistration registration = registry.addInterceptor(shiroInterceptor);
        registration.addPathPatterns("/**");
        registration.excludePathPatterns(anonPath);
    }

    /**
     * a. 告诉shiro不要使用默认的DefaultSubject创建对象，因为不能创建Session
     *
     */
    @Bean
    public SubjectFactory subjectFactory() {
        return new JwtSubject();
    }

    /**
     * ShiroFilterFactoryBean 处理拦截资源文件问题。
     * 注意：单独一个ShiroFilterFactoryBean配置是或报错的，以为在
     * 初始化ShiroFilterFactoryBean的时候需要注入：SecurityManager Filter Chain定义说明
     * 1、一个URL可以配置多个Filter，使用逗号分隔
     * 2、当设置多个过滤器时，全部验证通过，才视为通过
     * 3、部分过滤器可指定参数，如perms，roles
     */
    @Bean("shiroFilter")
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
        shiroFilter.setSecurityManager(securityManager);
        shiroFilter.setLoginUrl("/login");// 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
        shiroFilter.setSuccessUrl("/index");// 登录成功后要跳转的链接
        shiroFilter.setUnauthorizedUrl("/403");//未授权界面;

        Map<String, Filter> filterMap = new HashMap<String, Filter>(1);
        filterMap.put(jwtFilter, new JwtFilter());
        shiroFilter.setFilters(filterMap);

        Map<String,String> filterChainMap = new LinkedHashMap<String,String>();
//        anonPath.stream().forEach(anon->filterChainMap.put(anon, "anon"));
        for(String anon : anonPath){
            filterChainMap.put(anon, "anon");
        }

        filterChainMap.put("/logout", "logout");
        filterChainMap.put("/**", jwtFilter);
        shiroFilter.setFilterChainDefinitionMap(filterChainMap);

        return shiroFilter;
    }

    @Bean
    public JwtRealm shiroRealm(){
        JwtRealm jwtRealm = new JwtRealm();
//        jwtRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return jwtRealm;
    }


    @Bean//
    public SecurityManager securityManager(EhCacheManager ehCacheManager){
        DefaultWebSecurityManager securityManager =  new DefaultWebSecurityManager();
        securityManager.setRealm(shiroRealm());
        securityManager.setCacheManager(ehCacheManager);
//        securityManager.setSessionManager(sessionManager);
        //关闭shiro自带的session，详情见文档
        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
        subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
        securityManager.setSubjectDAO(subjectDAO);
        return securityManager;
    }
    /**
     * 创建shiro跟themeleaf交互的ShiroDialect
     * @return
     */
//    @Bean
//    public ShiroDialect getShiroDialect() {
//        return new ShiroDialect();
//    }

    @Bean
    public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator();
        proxyCreator.setProxyTargetClass(true);
        return proxyCreator;
    }
    /**
     * 开启shiro aop注解支持. 使用代理方式; 所以需要开启代码支持;
     *
     * @param securityManager 安全管理器
     * @return 授权Advisor
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }

    /**
     * shiro缓存管理器;
     * 需要注入对应的其它的实体类中：
     * 1、安全管理器：securityManager
     * 可见securityManager是整个shiro的核心；
     *
     * @return
     */
    @Bean
    public EhCacheManager ehCacheManager() {
        EhCacheManager em = new EhCacheManager();
        em.setCacheManagerConfigFile("classpath:ehcache.xml");
        return em;
    }


    @Bean
    public SimpleMappingExceptionResolver createSimpleMappingExceptionResolver() {
        SimpleMappingExceptionResolver r = new SimpleMappingExceptionResolver();

        r.setDefaultErrorView("error");    // No default
        r.setExceptionAttribute("exception");     // Default is "exception"
        //r.setWarnLogCategory("example.MvcLogger");     // No default

        Properties mappings = new Properties();
        //mappings.setProperty("DatabaseException", "databaseError");//数据库异常处理

        mappings.setProperty("UnauthorizedException","403");
        mappings.setProperty("UnknownAccountException","4031");
        mappings.setProperty("TokenExpiredException","401");
        mappings.setProperty("AuthenticationException","403");
        mappings.setProperty("IncorrectCredentialsException","403");
        mappings.setProperty("JWTVerificationException","403");

        r.setExceptionMappings(mappings);  // None by default
        return r;
    }

}
